﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using ShouldIt.Core;

namespace ShouldIt.Clr
{
    public static class ShouldExtensions
    {
		[Obsolete("Use Should().Equal() instead.")]
        public static T ShouldEqual<T>(this T o, T expected)
        {
            AssertProvidersContainer.Current.AreEqual(expected, o);
            return o;
        }

		[Obsolete("Use Should().Not.Equal() instead.")]
        public static T ShouldNotEqual<T>(this T o, T expected)
        {
            AssertProvidersContainer.Current.AreNotEqual(expected, o);
            return o;
        }

		[Obsolete("Use Should().Not.Be.Null() instead.")]
        public static T ShouldNotBeNull<T>(this T o)
        {
            AssertProvidersContainer.Current.IsNotNull(o);
            return o;
        }

		[Obsolete("Use Should().Be.Null() instead.")]
        public static T ShouldBeNull<T>(this T o)
        {
            AssertProvidersContainer.Current.IsNull(o);
            return o;
        }

		[Obsolete("Use Should().Not.Be.NullOrEmpty() instead.")]
        public static T ShouldNotBeNullOrEmpty<T>(this T o)
        {
            AssertProvidersContainer.Current.IsNotNull(o);
            AssertProvidersContainer.Current.IsFalse(o.ToString() == string.Empty);
            return o;
        }

		[Obsolete("Use Should().Not.Be.NullOrEmpty() instead.")]
        public static string ShouldNotBeNullOrEmpty(this string s)
        {
            AssertProvidersContainer.Current.IsFalse(string.IsNullOrEmpty(s));
            return s;
        }

		[Obsolete("Use Should().Be.NullOrEmpty() instead.")]
        public static Guid ShouldBeEmpty(this Guid g)
        {
            AssertProvidersContainer.Current.AreEqual(Guid.Empty, g);
            return g;
        }

		[Obsolete("Use Should().Not.Be.Empty() instead.")]
        public static Guid ShouldNotBeEmpty(this Guid g)
        {
            AssertProvidersContainer.Current.AreNotEqual(Guid.Empty, g);
            return g;
        }

		[Obsolete("Use Should().Be.True() instead.")]
        public static bool ShouldBeTrue(this bool b)
        {
            AssertProvidersContainer.Current.IsTrue(b);
            return true;
        }

		[Obsolete("Use Should().Be.ConvertableTo() instead.")]
    	public static T ShouldBeConvertable<T>(this string s)
        {
            try
            {
                var converter = TypeDescriptor.GetConverter(typeof (T));
                return (T) converter.ConvertFrom(s);
            }
            catch (Exception ex)
            {
                AssertProvidersContainer.Current.Fail("Could not convert '{0}' to {1}.  {3}", s, typeof (T), ex.ToString());
                return default(T);
            }
        }

		[Obsolete("Use Should().Be.SameAs() instead.")]
    	public static T ShouldBeSameAs<T>(this T obj, T expected)
        {
            AssertProvidersContainer.Current.AreSame(expected, obj);
            return obj;
        }

		[Obsolete("Use Should().Not.Be.SameAs() instead.")]
    	public static T ShouldNotBeSameAs<T>(this T o, T expected)
        {
            AssertProvidersContainer.Current.AreNotSame(expected, o);
            return o;
        }

		[Obsolete("Use Should().Be.False() instead.")]
    	public static bool ShouldBeFalse(this bool b)
        {
            AssertProvidersContainer.Current.IsFalse(b);
            return b;
        }

		[Obsolete("Use Should().Be.Today() instead.")]
        public static DateTime ShouldBeToday(this DateTime d)
        {
            d.Date.ShouldEqual(DateTime.Today);
            return d;
        }

		[Obsolete("Use Should().Contain() instead.")]
        public static string ShouldContain(this string s, string subString)
        {
            AssertProvidersContainer.Current.IsSubstringOf(s, subString);
            return s;
        }

		[Obsolete("Use Should().EndWith() instead.")]
        public static string ShouldEndWith(this string s, string subString)
        {
            if (!s.EndsWith(subString))
            {
                AssertProvidersContainer.Current.Fail("Expected string '{0}' to end with '{1}', but it did not.", s, subString);
            }
            return s;
        }

		[Obsolete("Use Should().Be.OfType<T>() instead.")]
        public static T ShouldBeOfType<T>(this object o)
        {
            AssertProvidersContainer.Current.IsInstanceOfType(o, typeof (T));
            return (T)o;
        }

		[Obsolete("Use Should().Be.OfType() instead.")]
        public static object ShouldBeOfType(this object o, Type expectedType)
        {
            AssertProvidersContainer.Current.IsInstanceOfType(o, expectedType);
            return o;
        }

		[Obsolete("Use Should().Not.Be.OfType<T>() instead.")]
        public static object ShouldNotBeOfType<T>(this object o)
        {
            AssertProvidersContainer.Current.IsNotInstanceOfType(o, typeof (T));
            return o;
        }

		[Obsolete("Use Should().Not.Be.OfType<T>() instead.")]
        public static object ShouldNotBeOfType(this object o, Type expectedType)
        {
            AssertProvidersContainer.Current.IsNotInstanceOfType(o, expectedType);
            return o;
        }

		[Obsolete("Use Should().Be.Equal() instead.")]
        public static MethodCallExpression ShouldEqual(this MethodCallExpression c, MethodCallExpression expectedCall)
        {
            AssertProvidersContainer.Current.AreEqual(c.Method, expectedCall.Method);
            for (var i = 0; i < c.Arguments.Count; i++)
            {
                AssertProvidersContainer.Current.AreEqual(
                    Expression.Lambda(expectedCall.Arguments[i]).Compile().DynamicInvoke(),
                    Expression.Lambda(c.Arguments[i]).Compile().DynamicInvoke());
            }
            return c;
        }

		[Obsolete("Use Should().Contain.One() instead.")]
        public static T ShouldContainOne<T>(this IEnumerable<T> e, Func<T, bool> predicate)
        {
            var match = e.ShouldContainAtLeastOne(predicate);
            if (match.Count() > 1)
            {
                AssertProvidersContainer.Current.Fail("Expecting 1 matching item in list.  Found {0}.", match.Count());
            }
            return match.First();
        }

		[Obsolete("Use Should().Contain.One() instead.")]
        public static T ShouldContainOne<T>(this IQueryable<T> q)
        {
            var match = q.ShouldContainAtLeastOne();
            if (match.Count() > 1)
            {
                AssertProvidersContainer.Current.Fail("Expecting 1 matching item in list.  Found {0}.", match.Count());
            }
            return match.First();
        }

		[Obsolete("Use Should().Contain.Item() instead.")]
        public static T ShouldContainOne<T>(this IEnumerable<T> e, T value)
        {
            return e.ShouldContainOne(x => x.Equals(value));
        }

		[Obsolete("Use Should().Contain.Any<T>()")]
        public static IEnumerable<T> ShouldContainAtLeastOne<T>(this IEnumerable<T> e, Func<T, bool> predicate)
        {
            var match = e.Where(predicate).ToList();
            if (match.Count() == 0)
            {
                AssertProvidersContainer.Current.Fail("Expecting at least 1 matching item in list.  Found 0.");
            }
            return match;
        }

		[Obsolete("Use Should().Contain.Any() instead.")]
        public static IEnumerable<T> ShouldContainAtLeastOne<T>(this IQueryable<T> q)
        {
            var match = q.ToList();
            if (match.Count() == 0)
            {
                AssertProvidersContainer.Current.Fail("Expecting at least 1 matching item in list.  Found 0.");
            }
            return match;
        }

		[Obsolete("Use Should().Not.Contain.Any<T>() instead.")]
        public static IEnumerable<T> ShouldNotContain<T>(this IEnumerable<T> e, Func<T, bool> predicate)
        {
            var match = e.Where(predicate).ToList();
            if (match.Count() != 0)
            {
                AssertProvidersContainer.Current.Fail("Expected 0 matching items in the list.  Found {0}.", match.Count());
            }
            return e;
        }

		[Obsolete("Use Should().Contain.Item() instead.")]
        public static T ShouldContain<T>(this IEnumerable<T> e, T item)
        {
            AssertProvidersContainer.Current.Contains(item, e);
            return item;
        }

		[Obsolete("Use Should().Not.Contain.Item()")]
        public static T ShouldNotContain<T>(this IEnumerable<T> e, T item)
        {
            AssertProvidersContainer.Current.NotContains(item, e);
            return item;
        }

		[Obsolete("Use Should().Count() instead.")]
        public static IEnumerable<T> ShouldCount<T>(this IEnumerable<T> e, int expectedCount)
        {
            AssertProvidersContainer.Current.AreEqual(expectedCount, e.Count());
            return e;
        }

		[Obsolete("Use Should().Count.Zero() instead.")]
        public static IEnumerable<T> ShouldBeEmpty<T>(this IEnumerable<T> e)
        {
            e.ShouldCount(0);
            return e;
        }

		[Obsolete("Use Should().Count.AtLeast() instead.")]
        public static IEnumerable<T> ShouldCountAtLeast<T>(this IEnumerable<T> e, int expectedCount)
        {
            AssertProvidersContainer.Current.GreaterOrEqual(expectedCount, e.Count());
            return e;
        }
    }
}